package com.upb.webserver.applicationorg;

import cn.hutool.core.collection.CollectionUtil;
import com.upb.webserver.application.ApplicationManager;
import com.upb.webserver.chain.ChainManager;
import com.upb.webserver.common.constant.Constant;
import com.upb.webserver.common.enums.PlatformEnum;
import com.upb.webserver.common.pojo.applicationorg.RspApplicationOrgVO;
import com.upb.webserver.common.pojo.base.BasePageResponse;
import com.upb.webserver.common.tools.JsonUtils;
import com.upb.webserver.common.tools.MybatisExampleTools;
import com.upb.webserver.company.CompanyDeveloperService;
import com.upb.webserver.dao.entity.TbApplicationOrg;
import com.upb.webserver.dao.entity.TbApplicationOrgExample;
import com.upb.webserver.dao.entity.TbChain;
import com.upb.webserver.dao.entity.TbOrg;
import com.upb.webserver.dao.mapper.TbApplicationOrgMapper;
import com.upb.webserver.dao.mapper.TbOrgMapper;
import com.upb.webserver.org.OrgManager;
import com.upb.webserver.org.OrgService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;


@Slf4j
@Service
public class ApplicationOrgService {
    @Autowired
    private CompanyDeveloperService companyDeveloperService;
    @Autowired
    private TbApplicationOrgMapper applicationOrgMapper;
    @Autowired
    private ApplicationManager applicationManager;
    @Autowired
    private ChainManager chainManager;
    @Autowired
    private OrgManager orgManager;
    @Autowired
    private OrgService orgService;
    @Autowired
    private TbOrgMapper orgMapper;


    /**
     * @param chainId
     * @param orgId
     */
    @Transactional
    public void saveApplicationOrg(Integer chainId, Integer applicationId, Integer orgId, Byte orgType) {
        log.info("start exec method [saveApplicationOrg]. chainId:{} applicationId:{} orgId:{} orgType:{}", chainId, applicationId, orgId, orgType);

        //check chainId
        TbChain tbChain = chainManager.verifyChainId(chainId);
        //check chainId
        applicationManager.verifyApplicationId(applicationId);
        //check org
        orgManager.verifyOrgId(orgId);

        if (CollectionUtil.isNotEmpty(applicationOrgMapper.selectByApplicationAndOrg(applicationId, orgId))) {
            log.info("found record by appId:{} and orgId:{}", applicationId, orgId);
            return;
        }

        //save chain-org
        TbApplicationOrg tbApplicationOrg = new TbApplicationOrg();
        tbApplicationOrg.setOrgId(orgId);
        tbApplicationOrg.setOrgType(orgType);
        tbApplicationOrg.setChainId(chainId);
        tbApplicationOrg.setApplicationId(applicationId);
        tbApplicationOrg.setChainType(tbChain.getChainType());
        tbApplicationOrg.setGmtCreate(new Date());
        tbApplicationOrg.setGmtModified(new Date());

        applicationOrgMapper.insert(tbApplicationOrg);
        log.info("success exec method [saveApplicationOrg]. chainId:{} orgId:{}", orgId);
    }


    /**
     * @param pageNumber
     * @param pageSize
     * @param applicationId
     * @return
     */
    public BasePageResponse queryApplicationOrgByPage(int pageNumber, int pageSize, Byte orgType, int applicationId) {
        log.info("start exec method [queryApplicationOrgByPage]. currentDeveloper:{} pageNumber:{} pageSize:{} applicationId:{}", pageNumber, pageSize, applicationId);
        BasePageResponse pageResponse = BasePageResponse.initialize();
        TbApplicationOrgExample example = MybatisExampleTools.initSamplePageExample(TbApplicationOrgExample.class, pageNumber, pageSize, new TbApplicationOrg(applicationId, orgType));
        pageResponse.setTotalCount(applicationOrgMapper.countByExample(example));
        if (pageResponse.getTotalCount() == 0) return pageResponse;

        List<RspApplicationOrgVO> rspList = new ArrayList<>();
        List<TbApplicationOrg> list = applicationOrgMapper.selectByExample(example);

        list.stream().forEach(tbAppOrg -> {
            RspApplicationOrgVO applicationOrgVO = new RspApplicationOrgVO();
            BeanUtils.copyProperties(tbAppOrg, applicationOrgVO);

            TbOrg tbOrg = orgManager.verifyOrgId(tbAppOrg.getOrgId());
            applicationOrgVO.setOrgName(tbOrg.getName());
            applicationOrgVO.setOrgCompanyId(tbOrg.getCompanyId());
            rspList.add(applicationOrgVO);
        });

        pageResponse.setData(rspList);

        log.info("success exec method [queryApplicationOrgByPage]. result:{}", JsonUtils.objToString(pageResponse));
        return pageResponse;
    }


    /**
     * @param creatorPlatform
     * @param creatorId
     * @param applicationId
     * @return
     */
    public String getCreatorOrgName(Byte creatorPlatform, int creatorId, int applicationId) {
        log.info("start exec method [getCreatorOrgName]. creatorPlatform:{} creatorId:{} applicationId:{}", creatorPlatform, creatorId, applicationId);
        if (PlatformEnum.DEV_OPS.getId() == creatorPlatform) {
            log.info("finish exec method [getCreatorOrgName] .result:{}", Constant.DEV_OPS_ADMIN_NAME_ZH);
            return Constant.DEV_OPS_ADMIN_NAME_ZH;
        }

        if (PlatformEnum.DEVELOPER.getId() != creatorPlatform) {
            log.warn("fail exec method [getCreatorOrgName].not support creatorPlatform:{}", creatorPlatform);
            return null;
        }

        //get orgIdList by creatorId
        Set<Integer> orgIdOfCreatorSet = orgService.getOrgIdSetByDeveloperId(creatorId);

        //get orgIdList by applicationId
        TbApplicationOrgExample example = MybatisExampleTools.initSampleExample(TbApplicationOrgExample.class, new TbApplicationOrg(applicationId, null));
        List<TbApplicationOrg> appOrgList = applicationOrgMapper.selectByExample(example);
        if (CollectionUtil.isEmpty(orgIdOfCreatorSet) || CollectionUtil.isEmpty(appOrgList)) {
            log.warn("fail exec method [getCreatorOrgName].  orgIdOfCreatorSet:{} appOrgList:{}", JsonUtils.objToString(orgIdOfCreatorSet), JsonUtils.objToString(appOrgList));
            return null;
        }

        //case any org of creator
        Integer creatorOrgId = appOrgList.stream()
                .filter(ao -> orgIdOfCreatorSet.contains(ao.getOrgId()))
                .findFirst()
                .map(aof -> aof.getOrgId())
                .orElse(null);

        if (Objects.isNull(creatorOrgId)) {
            log.warn("fail exec method [getCreatorOrgName], not found org by  creatorId:{} and applicationId:{}", creatorId, applicationId);
            return null;
        }

        String orgName = orgMapper.selectNameByPrimaryKey(creatorOrgId);
        log.info("success exec method [getCreatorOrgName],  creatorId:{} and applicationId:{}  result:{}", creatorId, applicationId, orgName);
        return orgName;
    }


    /**
     * @param applicationId
     * @param developerId
     * @return
     */
    public Set<Integer> listOrgIdByApplicationAndDeveloper(int applicationId, int developerId) {
        log.info("start exec method [listOrgIdByApplicationAndDeveloper]. applicationId:{} developerId:{}", applicationId, developerId);
        List<TbApplicationOrg> appOrgList = listByApplicationAndDeveloper(applicationId, developerId);
        if (CollectionUtil.isEmpty(appOrgList))
            return new HashSet<>();

        Set<Integer> orgIdSet = appOrgList.stream().map(ao -> ao.getOrgId()).collect(Collectors.toSet());

        log.info("finish exec method [getOrgByApplicationAndDeveloper]. applicationId:{} developerId:{} result:{}", applicationId, developerId, JsonUtils.objToString(orgIdSet));
        return orgIdSet;
    }


    /**
     * @param applicationId
     * @param developerId
     * @return
     */
    public List<TbApplicationOrg> listByApplicationAndDeveloper(int applicationId, int developerId) {
        log.info("start exec method [getOrgByApplicationAndDeveloper]. applicationId:{} developerId:{}", applicationId, developerId);
        Set<Integer> orgIdSet = orgService.getOrgIdSetByDeveloperId(developerId);
        if (CollectionUtil.isEmpty(orgIdSet))
            return null;

        TbApplicationOrgExample example = new TbApplicationOrgExample();
        TbApplicationOrgExample.Criteria criteria = example.createCriteria();
        criteria.andOrgIdIn(new ArrayList<>(orgIdSet));
        criteria.andApplicationIdEqualTo(applicationId);

        List<TbApplicationOrg> result = applicationOrgMapper.selectByExample(example);
        log.info("finish exec method [getOrgByApplicationAndDeveloper]. applicationId:{} developerId:{} result:{}", applicationId, developerId, JsonUtils.objToString(result));
        return result;
    }
}
